package net.sf.calibur.ai.pathfinder;

public class AStarNode implements Comparable<AStarNode> {
	private final static int[][] GMatrix = { 
		{ 14, 10, 14 }, 
		{ 10, 10, 10 },
		{ 14, 10, 14 } 
	};

	private int g = 0; // 从起点source移动到当前点的耗费
	private int h = 0; // 从当前点到终点的估值耗费
	private int f = 0; // f = g + h

	private int x;
	private int y;

	private AStarNode father = null; // 父结点

	public static AStarNode newInstance(int x, int y) {
		return new AStarNode(x, y);
	}

	AStarNode(int x, int y) {
		this.x = x;
		this.y = y;
	}

	public void clear() {
		g = h = f = 0;
		father = null;
	}

	public int getX() {
		return x;
	}

	public void setX(int x) {
		this.x = x;
	}

	public int getY() {
		return y;
	}

	public void setY(int y) {
		this.y = y;
	}

	public AStarNode getFather() {
		return father;
	}

	public void setFather(AStarNode father) {
		this.father = father;
	}

	public void init(AStarNode target) {
		this.g = 0;
		this.h = heuristicCostEstimate(this, target);
		this.f = g + h;
	}

	/**
	 * 计算H
	 * 
	 * @param source
	 * @param target
	 * @return
	 */
	public int heuristicCostEstimate(AStarNode source, AStarNode target) {
		return (Math.abs(source.x - target.x) + Math.abs(source.y - target.y))
				* GMatrix[1][1];
	}

	@Override
	public int compareTo(AStarNode o) {
		return this.f < o.f ? -1 : 1;
	}

	@Override
	public boolean equals(Object obj) {
		try {
			AStarNode node = (AStarNode) obj;
			return node.x == this.x && node.y == this.y;
		} catch (Throwable t) {
			return false;
		}
	}

	@Override
	public String toString() {
		return new StringBuilder().append(x).append(", ").append(y).toString();
	}

	public int calculatorF(AStarNode father, AStarNode target) {
		/*
		 * 地图中还有两个因素可以影响寻路，危险程度（有玩家和NPC正在战斗）和地图移动速度（河流、沼泽）。
		 * h值是当前节点离目标的开销预估，因为距离较远，只能维持当前算法。
		 * g值是当前节点与父节点的计算，g值的计算中，可以加入地图的影响因素。当前节点的“危险度”和“速度”，
		 * “速度”是地图相对静态的数据，地表确定后，速度是固定的。
		 * “危险度”是动态的数据，根据玩家与npc、其他玩家在某个位置PK，呈圆形辐射递减，叠加到地图块的“危险度”属性上。
		 */
		this.g = getDistinctG(father);
		this.h = heuristicCostEstimate(this, target);
		this.f = g + h;
		this.father = father;
		return f;
	}

	public int getDistinctG(AStarNode father) {
		int offsetX = x - father.x;
		int offsetY = y - father.y;
		return GMatrix[offsetX + 1][offsetY + 1] + father.g;

	}

	public int getG() {
		return g;
	}

	/**
	 * 是否比指定的点更好
	 * 
	 * @param node
	 * @return
	 */
	public boolean isBetter(AStarNode node) {
		return isGBetter(node);
	}

	public boolean isGBetter(AStarNode node) {
		return g + getDistinctG(node) < node.g;
	}

	public boolean isFBetter(AStarNode node) {
		return f < node.f;
	}

	public int getF() {
		return f;
	}
}